/** Promise实现
 * https://juejin.cn/post/7000572692201996296
 * 小步走：
 *  1.核心逻辑实现
 *      提供了state、vlaue、reason、resolve()、reject()、then()
 *  2.实现异步逻辑
 *      提供了onFulfilledCallback、onRejectedCallback保存then里面的两个方法
 *  3.实现 then 方法多次调用添加多个处理函数
 *      修改onFulfilledCallback、onRejectedCallback成数组，存放不同的then传入的方法
 *  4.实现 then 方法的链式调用
 *      修改then方法的return;return一个新的promise，判断传入的then方法，返回的是不是Promise（这里有点绕）
 */
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
  constructor(executor) {
    /** 接受一个执行器，并立即执行 */
    executor(this.resolve, this.reject);
  }
  state = PENDING; // 当前状态，只能修改一次
  promiseResult = null; // 结果值，成功或失败

  // 实现异步逻辑
  onFulfilledCallback = []; // 存放成功回调
  onRejectedCallback = []; // 存放失败回调


  resolve = (value) => {
    if (this.state !== PENDING) return;
    this.state = FULFILLED;
    this.promiseResult = value;
    while(this.onFulfilledCallback.length) {
      this.onFulfilledCallback.shift()()
    }
  }

  reject = (reason) => {
    if (this.state !== PENDING) return;
    this.state = REJECTED;
    this.promiseResult = reason;
    while(this.onRejectedCallback.length) {
      this.onRejectedCallback.shift()()
    }
  }

  then(onFulfilled, onRejected) {
    // 这里定义是为了，如果then方法，什么都么有传，可以实现“值穿透”
    if (typeof onFulfilled !== "function") {
      onFulfilled = val => val;
    }
    
    if (typeof onRejected !== "function") {
      onRejected = val => val;
    }
    return new MyPromise((nextResolve, nextRejected) => {
       /** 实现链式调用使用 */
      const returnPromise = (func) => {
        try {
          const res = func(this.promiseResult);
          if(res instanceof MyPromise) { // 如果then传入的方法，返回的是一个promise
            res.then(nextResolve, nextRejected)
          } else {
            nextResolve(res)
          }
        } catch(err) {
          onRejected(err);
        }
      }
      if (this.state === FULFILLED) {
        returnPromise(onFulfilled);
      } else if (this.state === REJECTED) {
        returnPromise(onRejected);
      } else if (this.state === PENDING) {
        // 因为不知道后面状态的变化情况，所以将成功回调和失败回调存储起来
        // 等到执行成功失败函数的时候再传递
        this.onFulfilledCallback.push(() => returnPromise(onFulfilled));
        this.onRejectedCallback.push(() => returnPromise(onRejected));
      }
    })
  }

  catch(onRejected) {
    this.then(undefined, onRejected);
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      let count = 0;
      let arr = []
      for (let i = 0; i < promises.length; i ++) {
        promises[i].then((res)=> {
          count++;
          arr[i] = res;
          if (count === promises.length) {
            resolve(arr)
          }
        }, r => {
          reject(r)
        })
      }
    })
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      for (var i = 0; i < promises.length;i++) {
        promises[i].then((r) => {
          resolve(r)
        }, r => reject(r))
      }
    })
  }
}


// -------------------------------------------------------------------------------------------------------------

// const promise = new MyPromise((resolve, reject) => {
//     setTimeout(() => {
//     resolve('success')
//     // reject('err')
//   }, 1000)
// })

// const p1 = promise.then(value => {
//  console.log('r1', value)
//  return "1111"
// })
// console.info("p1.state", p1.state)
// const p2 = p1.then(v => {
//   console.info('r2', v)
//   return new MyPromise((r, j) => {
//     r(888)
//   })
// })
// console.info("p2.state", p2.state)
// const p3 = p2.then(v1 => {
//   console.info('r3', v1)
//   return 1;
// }).then(() => {})


const p4 = MyPromise.race([
  new MyPromise(r => {r(1)}),
  new MyPromise(r => {r(2)}),
  new MyPromise(r => {setTimeout(() =>{ r(3) }, 1000)}),
])
p4.then(res => console.info(res)).catch(err=> console.info(e));

// promise.then(value => {
//   console.log('resolve2', value)
//  }, reason => {
//   console.log('reject', reason)
//  })
 
//  promise.then(value => {
//   console.log('resolve3', value)
//  }, reason => {
//   console.log('reject', reason)
//  })
 
  
// -------------------------------------------------------------------------------------------------------------


// const promise1 = new Promise((resolve) => {
//   setTimeout(() => {
//     resolve("sucess")
//   }, 1000)
// })
// promise1.then(value => {
//   console.log('resolve1', value)
//   return 111
//  }).then(v => {
//    console.info('resolve2', v)
//    return new Promise((r) => {
//     r(9999)
//    })
//  }).then(v => {
//    console.info(v)
//  })
 